package server

import (
	"context"
	"encoding/json"
	"fmt"
	global2 "longmen/server/config/global"
	"longmen/server/internal/rpc/tencentim/chat"
	"longmen/server/internal/services/consumers/publisher"
	"longmen/server/pkg/common/helper/blackWorlds"
	time2 "longmen/server/pkg/common/helper/timehelper"
	"longmen/server/pkg/common/helper/util"
	"longmen/server/pkg/common/services"
	"longmen/server/pkg/db/mysql"
	"longmen/server/pkg/db/mysql/db_live"
	"longmen/server/pkg/db/mysql/db_main"
	"longmen/server/pkg/db/mysql/models/models_main"
	"longmen/server/pkg/db/redis/cache"
	pb "longmen/server/pkg/protobuf"
	"regexp"
	"time"

	"longmen/server/pkg/common/api_models"

	"github.com/jinzhu/copier"
	"github.com/labstack/echo/v4"
)

func (s *Server) UpdateNickName(ctx context.Context, req *pb.UpdateNickNameReq) (*pb.UpdateNickNameResp, error) {
	var service *services.Service
	count, err := service.GetUserByNickName(req.Nickname, 0)
	if err != nil {
		return nil, err
	}
	if count > 0 {
		return nil, fmt.Errorf(global2.Lang.T("nickname_exists"))
	}
	accountRx := regexp.MustCompile("^[\u4e00-\u9fa5_a-zA-Z0-9_]{2,8}$")
	req.Nickname = blackWorlds.BlackWorInstance.ReplaceWithAsterisk(req.Nickname)
	checkRx := accountRx.MatchString(req.Nickname)
	if !checkRx {
		return nil, fmt.Errorf(global2.Lang.T("invalid_nickname"))
	}
	user, err := mysql.GetUserParam(map[string]interface{}{"id": req.Uid})
	if time.Now().Unix()-user.NickNameTime < 86400*7 {
		return nil, fmt.Errorf(global2.Lang.T("Nickname_can_be_changed_only_once_in_7days"))
	}
	user.NickName = req.Nickname
	user.NickNameTime = time.Now().Unix()
	err = service.UpdateUser([]string{"nick_name", "nick_name_time"}, user)
	if err != nil {
		return nil, err
	}
	chat.SetClientUserName(int(req.GetUid()), req.Nickname)
	cache.DelUserFullCache(user.Id)
	return &pb.UpdateNickNameResp{
		Msg: global2.Lang.T("success"),
	}, nil
}
func (s *Server) GetUserInfo(ctx context.Context, req *pb.GetUserInfoReq) (*pb.GetUserInfoResp, error) {

	userid := int(req.GetUid())
	user, err := s.GetUserById(userid)
	if err != nil {
		return nil, err
	}
	resp := new(pb.GetUserInfoResp)
	resp.Account = user.Account
	resp.NickName = user.NickName
	resp.Avatar = user.Avatar
	resp.Diamond = uint32(user.Diamond)
	resp.Mobile = user.Mobile
	resp.Gold = uint32(user.Gold)
	resp.ReceiveVip = uint32(user.ReceiveVip)
	noticeTime, err := s.getLatestNotice(user.Id)
	if err == nil {
		if noticeTime > user.ReadTime.Unix() {
			resp.HasNotice = true
		}
	}

	//关注数量
	resp.AttentCount = uint32(len(cache.GetUserAttentAnchorIds(user.Id)))
	//粉丝数量
	resp.FansCount = uint32(cache.GetFansCount(user.Id))
	//送礼数量
	resp.GiftSpend = uint32(cache.GetSendGiftCount(user.Id))
	//用户资料
	profile, err := s.getUserProfile(userid)
	if err != nil {
		return nil, err
	}
	resp.Sex = uint32(profile.Gender)
	level, err := s.getUserLevel(user.Point) //用户经验值查询对应等级
	if err != nil {
		return nil, err
	}

	record := db_main.GetNobleInUse(uint64(userid))
	resp.NobleId = uint32(record.NobleId)
	// 用户开通过VIP，且没有到期
	if record.Id > 0 {
		resp.RankId = uint32(record.RankId)
		resp.VipName = record.Name
		resp.VipLeftDay = time2.GetLeftDays(record.Expiration)
		resp.VipFrom = int32(record.From)
		resp.GiftDiscount = int32(record.GiftDiscount)
	}
	err = copier.Copy(resp, level) // 对象拷贝等级信息
	if err != nil {
		return nil, err
	}
	if user.Password != "" {
		resp.HasPassword = true
	}
	//// 用户没有开通VIP，已经领取VIP盲盒的时候返回领取VIP信息
	//if user.ReceiveVip > 0 && record.NobleId == 0 {
	//	nobleRecord, err2 := repository.GetNobleRecordByUid(userid)
	//	if err2 == nil {
	//		//resp.RankId = uint32(nobleRecord.RankId)//fixme
	//		//resp.VipName = nobleRecord.Name
	//		resp.VipLeftDay = getLeftDays(nobleRecord.Expiration)
	//	} else {
	//		return nil, err
	//	}
	//}
	resp.IsGuessHost = uint32(user.IsGuessHost)
	resp.TDeactive = user.DeactiveTime.Format("2006-01-02 15:04")
	resp.Status = uint32(user.Status)
	resp.NickNameTime = uint64(user.NickNameTime)

	// 主播简介
	resp.Intro = user.Intro
	resp.Banner = user.Banner

	if user.RegSourceId != "" {
		//buff, err := json.Marshal(user)
		//if err != nil {
		//	global.Log.Errorf("set source stat error[%+v]: ", err)
		//} else {
		//	err = global.GetNats().Publish(util.STAT_USER_LOGIN_CHANNEL, buff)
		//	if err != nil {
		//		global.Log.Errorf("Nats publish chanel %s", err.Error())
		//	}
		//}

		err = global2.PublishChannelStats.Send(publisher.LoginChannelStats, user)
		if err != nil {
			global2.Log.Errorf("Nats publish chanel %s", err.Error())
		}
	}
	//增加坐骑
	propsItem := db_main.GetProps(req.GetUid())
	resp.Item = &pb.PropsItem{}
	copier.Copy(resp.Item, propsItem)
	/**/

	//增加观看券是否在使用中 true不消耗 false弹窗消耗
	checked, err := db_live.TicketINLive(int(user.Id), 0, cache.GetConfigPub().TicketSwitch)
	if err != nil {
		return nil, err
	}
	resp.TicketUse = checked
	return resp, nil
}

func (s *Server) GetUserById(uid int) (*models_main.User, error) {
	result, err := cache.GetUserFullInfo(uid)
	if err != nil {
		return nil, err
	}
	return result, nil
}

// getLatestNotice 最后阅读消息通知时间
func (s *Server) getLatestNotice(uId int) (int64, error) {
	list, err := s.getNoticeList(uId, 1, 1)
	if err != nil {
		return 0, err
	}

	var creatTime int64
	for _, notice := range list.GetNoticeLsit {
		creatTime = notice.CreateTime
		break
	}
	return creatTime, err
}

func (s *Server) getUserProfile(id int) (*models_main.UserProfile, error) {
	return db_main.GetUserProfileParam(map[string]interface{}{"uid": id})
}

/* 包内部使用的方法，请用小写字母打头 */
// getNoticeList
func (s *Server) getNoticeList(uId, page, size int) (*pb.GetNoticeListResp, error) {
	var (
		condition = echo.Map{
			"or": []interface{}{"user_id = ? or user_id = 0", uId},
		}
	)

	//// 当前用户的站内通知
	//exclusiveList, err := repository.GetNoticeList(echo.Map{"user_id": uId}, page, size)
	//if err != nil {
	//	return nil, err
	//}
	//
	//// 所有用户的站内通知
	//commonList, err := repository.GetNoticeList(echo.Map{"user_id": 0}, page, size)
	//if err != nil {
	//	return nil, err
	//}

	//List := append(exclusiveList, commonList...)

	List, err := db_main.GetNoticeList(condition, page, size)
	if err != nil {
		return nil, err
	}

	var noticeList []*pb.GetNoticeList
	for _, v := range List {
		noticeList = append(noticeList, &pb.GetNoticeList{
			ImageUrl:   v.ImageUrl,
			CreateTime: v.CreatedAt.Unix(),
			Content:    v.Content,
			Link:       v.Link,
		})
	}

	return &pb.GetNoticeListResp{
		GetNoticeLsit: noticeList,
	}, nil
}

// 取默认头像列表，从缓存中取
func (s *Server) GetDefultAvatars(ctx context.Context, req *pb.GetDefultAvatarsReq) (*pb.GetDefultAvatarsResp, error) {
	list := []models_main.Avatars{}
	sAvatars := cache.GetDefultAvatars()
	if len(sAvatars) > 0 {
		err := json.Unmarshal([]byte(sAvatars), &list)
		if err != nil {
			global2.Log.Error(err)
			return nil, err
		}
	}
	slice := make([]*pb.DefultAvatar, 0)
	for _, avatar := range list {
		if req.Role <= 1 && avatar.RoleType != 1 { //如果要的是用户或为0，那专家的不给
			continue
		}
		slice = append(slice, &pb.DefultAvatar{
			Id:       int64(avatar.Id),
			ImageUrl: avatar.ImageUrl,
		})
	}
	return &pb.GetDefultAvatarsResp{
		DefultAvatar: slice,
	}, nil
}

func (s *Server) calculateUserLevel(point uint32) ([]*models_main.UserLevelRule, uint8, error) {
	var (
		err   error
		level uint8
		fName = "CalculateUserLevel"
		rule  []*models_main.UserLevelRule
	)

	if rule, err = cache.GetUserLevelRule(); err != nil {
		return nil, 0, fmt.Errorf("%s %s", util.Convert(fName), err.Error())
	}

	for i := 0; i < len(rule)-1; i++ {
		for j := 0; j < len(rule)-1-i; j++ {
			if rule[j].Level > rule[j+1].Level {
				rule[j], rule[j+1] = rule[j+1], rule[j]
			}
		}
	}

	for i := 0; i < len(rule); i++ {
		if point >= rule[i].Point {
			level = rule[i].Level
		} else {
			break
		}
	}

	return rule, level, nil
}

func (s *Server) getUserLevel(userPoint int) (*api_models.Level, error) {
	fName := "GetUserLevel"
	var upgradePoint uint32 //指定等级所需经验
	var process uint32      //当前等级进度
	var difference uint32   //获取用户经验值,计算出level
	var remainder uint32    //获取用户经验值,计算出level
	rule, level, err := s.calculateUserLevel(uint32(userPoint))
	global2.Log.Debugf("用户等级:getUserLevel  rule：%v ,level:%v", rule, level)
	if err != nil {
		return nil, fmt.Errorf("%s%s", util.Convert(fName), err)
	}

	for i := 0; i < len(rule); i++ {
		if level == rule[i].Level-1 {
			upgradePoint = rule[i].Point
			if i > 0 {
				process = uint32(userPoint - int(rule[i-1].Point))
				difference = rule[i].Point - rule[i-1].Point
				break
			}
			process = uint32(userPoint) //0级别
			difference = rule[i].Point
			break
		}
	}

	if upgradePoint > uint32(userPoint) {
		remainder = upgradePoint - uint32(userPoint)
	}

	return &api_models.Level{
		Level:        level,
		Point:        uint32(userPoint),
		UpgradePoint: upgradePoint,
		Process:      process,
		Difference:   difference,
		Remainder:    remainder,
	}, nil
}
